package com.education.platform.common.redis;



import com.education.platform.common.util.CollectionsUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.*;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.util.SafeEncoder;


import java.util.*;

/**
 * redis工具
 */
public class RedisUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtils.class);

    private JedisPool jedisPool;
    private static volatile RedisUtils redisUtils;
    private RedisUtils(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }
    public void destroy() {
        jedisPool.destroy();
    }
    public static RedisUtils getInstance(JedisPoolConfig poolConfig, String host, int port,
                                         int timeout, String password, int database) {
        if (redisUtils == null) {
            synchronized (RedisUtils.class) {
                if (redisUtils == null) {
                    JedisPool jedisPool = new JedisPool(poolConfig, host, port, timeout, password, database);
                    redisUtils = new RedisUtils(jedisPool);
                }
            }
        }
        return redisUtils;
    }
    /**
     * 是否存在key
     * @param key
     * @return
     */
    public Boolean exists(String key) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.error("Key can not be empty!");
            return false;
        }
        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.exists(SafeEncoder.encode(key));
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis exists", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis exists (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return false;
    }


    /**
     * 设置过期时间
     * @param key
     * @param seconds
     * @return
     */
    public Long expire(String key, int seconds) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.error("Key can not be empty!");
            return 0L;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.expire(SafeEncoder.encode(key), seconds);
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis expire", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis expire (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return 0L;
    }

    /**
     * 获取剩余过期时间
     * @param key
     * @return
     */
    public Long ttl(String key) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.error("Key can not be empty!");
            return 0L;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.ttl(SafeEncoder.encode(key));
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis ttl", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis ttl (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return 0L;
    }

    /**
     * 删除
     * @param key
     * @return
     */
    public Long del(String key) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.error("Key can not be empty!");
            return 0L;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.del(SafeEncoder.encode(key));
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis del", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis del (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return 0L;
    }

    /**
     * 字符串结构
     * @param key
     * @param seconds
     * @param value
     * @return
     */
    public String setString(String key, final int seconds, final String value) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.error("Key can not be empty!");
            return "failed";
        }
        if (StringUtils.isEmpty(value)) {
            LOGGER.info("Value can not be empty!");
            return "failed";
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            if (seconds > 0) {
                return jedis.setex(key, seconds, value);
            } else {
                return jedis.set(key, value);
            }
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis rpush", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis rpush (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return "failed";
    }


    /**
     * 获取字符串value
     * @param key
     * @return
     */
    public String getString(String key) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.error("Key can not be empty!");
            return "failed";
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.get(key);
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis getString", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis getString (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return null;
    }

    /**
     * hash是否存在field
     * @param key
     * @param field
     * @return
     */
    public Boolean hexists(String key, final String field) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return false;
        }
        if (StringUtils.isEmpty(field)) {
            LOGGER.info("Field can not be empty!");
            return false;
        }

        Long start = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.hexists(SafeEncoder.encode(key), SafeEncoder.encode(field));
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis hexists", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis hexists (" + key + ") took " + (System.currentTimeMillis() - start) + " ms");
        }
        return false;
    }


    /**
     * 获取集合元素个数
     * @param key
     * @return
     */
    public Long zcard(String key) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return null;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.zcard(SafeEncoder.encode(key));
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis zcard", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis zcard (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return null;
    }






    public Jedis getResource() {
        return jedisPool.getResource();
    }


    public void returnResource(Jedis jedis) {
        if (jedis != null) {
            jedis.close();

        }
    }







    /*****/

    /**
     *
     * @param key
     * @param field
     * @param value   正数表示+    负数表示-
     * @return
     */
    public Long hincrBy(String key,String field,long value) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.error("Key can not be empty!");
            return null;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();

            return jedis.hincrBy(key,field,value);
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis hincrBy", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis hincrBy (" + key + "["+field+"]) took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return null;
    }

    /**
     * 添加有序集合元素
     * @param key
     * @param score
     * @param member
     * @return
     */
    public Long zaddStr(String key, double score, String member) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return 0L;
        }
        if (null == member) {
            LOGGER.info("Member can not be empty!");
            return 0L;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();

            return jedis.zadd(key, score, member);
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis zadd", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis zadd (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return 0L;
    }

    /**
     * 倒排
     * @param key
     * @param start
     * @param end
     * @return
     */
    public  Set zrevrangeWithScores(String key, long start, long end) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return null;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            Set<Tuple> set = jedis.zrevrangeWithScores(SafeEncoder.encode(key), start, end);
            if (CollectionsUtils.isEmpty(set)) {
                return null;
            }
            return set;
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis zrevrange", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis zrevrange (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return null;
    }

    /**
     * 增加
     * @param key
     * @param score
     * @param member
     * @return
     */
    public Double zincrby(String key, double score, String member) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return 0D;
        }
        if (null == member) {
            LOGGER.info("Member can not be empty!");
            return 0D;
        }

        Long begin = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();

            return jedis.zincrby(key, score, member);
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis zrem", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis zrem (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
        }
        return 0D;
    }


    public Long hsetStr(String key, final String field, final String value) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return null;
        }
        if (StringUtils.isEmpty(field)) {
            LOGGER.info("Field can not be empty!");
            return null;
        }
        if (null == value) {
            LOGGER.info("Value can not be empty!");
            return null;
        }

        Long start = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            return jedis.hset(key, field, value);
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis hset", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis hset (" + key + ") took " + (System.currentTimeMillis() - start) + " ms");
        }
        return null;
    }
    public String hgetStr(String key, final String field) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return null;
        }
        if (StringUtils.isEmpty(field)) {
            LOGGER.info("Field can not be empty!");
            return null;
        }

        Long start = System.currentTimeMillis();
        Jedis jedis = null;

        try {
            jedis = getResource();
            return jedis.hget(key,field);
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis hget", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis hget (" + key + ") took " + (System.currentTimeMillis() - start) + " ms");
        }
        return null;
    }

    public Boolean hmsetStr(String key, final Map<String, String> map) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return false;
        }
        if (CollectionsUtils.isEmpty(map)) {
            LOGGER.info("Map can not be empty!");
            return false;
        }

        Long start = System.currentTimeMillis();
        Jedis jedis = null;
        try {
            jedis = getResource();
            jedis.hmset(key,map);
            return true;
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis hmset", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis hmset (" + key + ") took " + (System.currentTimeMillis() - start) + " ms");
        }
        return false;
    }

    /**
     * 获取hash
     * @param key
     * @return
     */
    public  Map<String,String> hgetAllStr(String key) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return null;
        }

        Long start = System.currentTimeMillis();
        Jedis jedis = null;
        try {

            jedis = getResource();

            Map<String,String> map = jedis.hgetAll(key);
            return map;
        } catch (JedisConnectionException jce) {
            LOGGER.error(jce.getMessage(), jce);
        } catch (Exception e) {
            LOGGER.error("Redis hgetAll", e);
        } finally {
            returnResource(jedis);
            LOGGER.debug("Redis hgetAll (" + key + ") took " + (System.currentTimeMillis() - start) + " ms");
        }
        return null;
    }

    /**
     * 返回成员的分数
     * @param key
     * @param member
     * @return
     */
    public Double zscore(String key, String member) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return null;
        } else {
            Long begin = System.currentTimeMillis();
            Jedis jedis = null;

            try {
                jedis = this.getResource();
                Double var5 = jedis.zscore(key, member);
                return var5;
            } catch (JedisConnectionException var10) {
                LOGGER.error(var10.getMessage(), var10);
            } catch (Exception var11) {
                LOGGER.error("Redis zscore", var11);
            } finally {
                this.returnResource(jedis);
                LOGGER.debug("Redis zscore (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
            }

            return null;
        }
    }

    /**
     * 获取分数从大到小的排名位置索引
     * @param key
     * @param member
     * @return
     */
    public Long zrevrank(String key, String member) {
        if (StringUtils.isEmpty(key)) {
            LOGGER.info("Key can not be empty!");
            return 0L;
        } else if (null == member) {
            LOGGER.info("Member can not be empty!");
            return 0L;
        } else {
            Long begin = System.currentTimeMillis();
            Jedis jedis = null;

            try {
                jedis = this.getResource();
                Long var5 = jedis.zrevrank(key, member);
                return var5;
            } catch (JedisConnectionException var10) {
                LOGGER.error(var10.getMessage(), var10);
            } catch (Exception var11) {
                LOGGER.error("Redis zrank", var11);
            } finally {
                this.returnResource(jedis);
                LOGGER.debug("Redis zrank (" + key + ") took " + (System.currentTimeMillis() - begin) + " ms");
            }

            return 0L;
        }
    }

}
